package com.jz.community.basecomm.utils.rxbus;

import android.support.annotation.NonNull;

import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import io.reactivex.Observable;
import io.reactivex.functions.Predicate;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;

/**
 * Created by Tony.Fan on 2018/3/15 10:30
 */
public class RxBus {
    private static RxBus instance=new RxBus();

    private Subject bus = null;
    private HashMap<Object, CopyOnWriteArrayList<Subject>> maps = new HashMap<>();

    public RxBus() {
        bus = PublishSubject.create().toSerialized();
    }

    public static RxBus getInstance() {
        return instance;
    }

    @SuppressWarnings("unchecked")
    public <T> Observable<T> register(@NonNull Object tag, @NonNull Class<T> clazz) {
        CopyOnWriteArrayList<Subject> subjects = maps.get(tag);
        if (subjects == null) {
            subjects = new CopyOnWriteArrayList<>();
            maps.put(tag, subjects);
        }
        Subject<T> subject = PublishSubject.<T>create();
        subjects.add(subject);
        return subject;
    }

    @SuppressWarnings("unchecked")
    public void unregister(@NonNull Object tag, @NonNull Observable observable) {
        List<Subject> subjects = maps.get(tag);
        if (subjects != null) {
            subjects.remove((Subject) observable);
            if (subjects.isEmpty()) {
                maps.remove(tag);
            }
        }
    }

    /**
     * @param o tag 名字和 参数类名 必须一致
     */
    @SuppressWarnings("unchecked")
    public void post(@NonNull Object o) {
        post(o.getClass().getSimpleName(), o);
    }

    /**
     * @param tag tag名 可以和 object 类名不一致
     * @param o
     */
    @SuppressWarnings("unchecked")
    public void post(@NonNull Object tag, @NonNull Object o) {
        synchronized (maps) {
            CopyOnWriteArrayList<Subject> subjects = maps.get(tag);
            if (subjects != null && !subjects.isEmpty()) {
                for (Subject s : subjects) {
                    s.onNext(o);
                }

            }
        }

    }

    //根据传递的eventType类型 返回特定类型的eventType给观察者
    public <T extends Object> Observable<T> toObservable(final Class<T> eventType) {

        return bus.filter(new Predicate() {
            @Override
            public boolean test(Object o) throws Exception {
                return o.getClass() == eventType.getClass();
            }
        })
                .cast(eventType);
    }

}
